package com.jinyang.plugindemo.broadcast

import android.content.BroadcastReceiver
import android.content.Context
import android.content.IntentFilter
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.util.Log
import com.jinyang.plugindemo.log
import java.io.File
import java.lang.Exception
import java.util.ArrayList

/**
 * @Author:         LiuJinYang
 * @CreateDate:     2021/12/14
 * @Description:
 */
class BroadcastUtils {
    companion object {
        private val broadcastMap = HashMap<String, BroadcastReceiver>()

        fun registerBroadcastReceiver(context: Context, classLoader: ClassLoader, action: String, broadcastName: String) {
            log("BroadcastUtils.registerBroadcastReceiver")
            val receiver = classLoader.loadClass(broadcastName).newInstance() as BroadcastReceiver
            val intentFilter = IntentFilter(action)
            context.registerReceiver(receiver, intentFilter)
            broadcastMap[action] = receiver
        }

        fun unregisterBroadcastReceiver(context: Context, action: String) {
            log("BroadcastUtils.unregisterBroadcastReceiver")
            val receiver = broadcastMap.remove(action)
            if (receiver!=null) {
                context.unregisterReceiver(receiver)
            }
        }

        /**
         * 将插件apk的AndroidManifest.xml中静态注册的Receiver通过动态registerReceiver注册到宿主Context中
         */
        fun parserApkAction(context: Context, pluginPath: String?) {
            try {
                //实例化 PackageParser对象
                val mPackageParserClass = Class.forName("android.content.pm.PackageParser")
                val mPackageParser = mPackageParserClass.newInstance()
                // 1.执行此方法 public Package parsePackage(File packageFile, int flags)，就是为了，拿到Package
                val mPackageParserMethod = mPackageParserClass.getMethod(
                    "parsePackage",
                    File::class.java,
                    Int::class.javaPrimitiveType
                )
                val mPackage = mPackageParserMethod.invoke(
                    mPackageParser,
                    File(pluginPath),
                    PackageManager.GET_ACTIVITIES
                )
                //获取mPackage中的ArrayList<Activity> receivers属性
                val receiversField = mPackage.javaClass.getDeclaredField("receivers")
                val receivers = receiversField[mPackage]
                val arrayList = receivers as ArrayList<*>
                //此Activity不是组件的Activity,是PackageParser里面的内部类
                for (mActivity in arrayList) { // mActivity --> <receiver android:name=".StaticReceiver">
                    //通过反射拿到intents ArrayList<II> intents; 一个<receiver>标签可以对应多个Intent-Filter
                    val mComponentClass =
                        Class.forName("android.content.pm.PackageParser\$Component")
                    val intentsField = mComponentClass.getDeclaredField("intents")
                    val intents: ArrayList<IntentFilter> = intentsField[mActivity] as ArrayList<IntentFilter>
                    //上面是拿到了IntentFilter，下面就是获取组件的名字 activityInfo.name
                    /**
                     * 执行此方法，就能拿到 ActivityInfo
                     * public static final ActivityInfo generateActivityInfo(Activity a, int flags,
                     * PackageUserState state, int userId)
                     */
                    val mPackageUserState = Class.forName("android.content.pm.PackageUserState")
                    val mUserHandle = Class.forName("android.os.UserHandle")
                    val userId = mUserHandle.getMethod("getCallingUserId").invoke(null) as Int
                    val generateActivityInfoMethod = mPackageParserClass.getDeclaredMethod(
                        "generateActivityInfo",
                        mActivity.javaClass,
                        Int::class.javaPrimitiveType,
                        mPackageUserState,
                        Int::class.javaPrimitiveType
                    )
                    generateActivityInfoMethod.isAccessible = true
                    val mActivityInfo = generateActivityInfoMethod.invoke(
                        null,
                        mActivity,
                        0,
                        mPackageUserState.newInstance(),
                        userId
                    ) as ActivityInfo
                    val receiverClassName = mActivityInfo.name
                    Log.e("LJY_LOG", "receiverClassName : $receiverClassName")
                    val mStaticReceiverClass = context.classLoader.loadClass(receiverClassName)
                    val broadcastReceiver = mStaticReceiverClass.newInstance() as BroadcastReceiver
                    for (intentFilter in intents) {
                        Log.e(
                            "LJY_LOG",
                            "intentFilter mActions size " + intentFilter.countActions()
                        )
                        context.registerReceiver(broadcastReceiver, intentFilter)
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}